/*
package com.thread.threadfirst.http.loan.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.fugui.marvel.common.constants.CommonConstants;
import com.fugui.marvel.common.dto.Page;
import com.fugui.marvel.common.enums.*;
import com.fugui.marvel.common.utils.*;
import com.fugui.marvel.common.utils.httpclient.HttpClient;
import com.fugui.marvel.service.common.domain.loan.TLoanOrder;
import com.fugui.marvel.service.common.domain.loan.TLoanProduct;
import com.fugui.marvel.service.common.domain.user.TRealNameAuth;
import com.fugui.marvel.service.common.domain.user.TUser;
import com.fugui.marvel.service.common.domain.user.TUserAgential;
import com.fugui.marvel.service.common.dto.display.LeaderBoardJpaDTO;
import com.fugui.marvel.service.common.form.profitform.ProfitThreeForm;
import com.fugui.marvel.service.common.repository.loan.LoanOrderRepository;
import com.fugui.marvel.service.common.repository.loan.LoanProductRepository;
import com.fugui.marvel.service.common.service.fastdfs.UploadService;
import com.fugui.marvel.service.common.service.feign.client.loan.FeignLoanServiceClient;
import com.fugui.marvel.service.common.service.feign.client.notice.FeignNoticeSendClient;
import com.fugui.marvel.service.common.service.feign.client.payment.FeignProfitTaskServiceClient;
import com.fugui.marvel.service.common.service.feign.client.redis.FeignRedisServiceClient;
import com.fugui.marvel.service.common.service.feign.client.user.FeignAgentialAccountServiceClient;
import com.fugui.marvel.service.common.service.feign.client.user.FeignRealNameAuthServiceClient;
import com.fugui.marvel.service.common.service.feign.client.user.FeignUserRelationServiceClient;
import com.fugui.marvel.service.common.service.feign.client.user.FeignUserServiceClient;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.persistence.criteria.*;
import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;

*/
/**
 * @author saving
 * @date 2019/9/10
 * @description 贷款服务
 *//*

@Service
@RestController
@Api(value = "网贷接口服务", tags = "网贷接口服务")
@RefreshScope
public class LoanServiceImpl implements FeignLoanServiceClient{

	Logger logger = LoggerFactory.getLogger(LoanServiceImpl.class);

	*/
/**
	 * 生产地址
	 *//*

	@Value(value = "${weiqiatong.baseHost}")
	private String baseHost;

	*/
/**
	 * 站点id
	 *//*

	@Value(value = "${weiqiatong.oemID}")
	private String oemID;

	*/
/**
	 * 商户号
	 *//*

	@Value(value = "${weiqiatong.merchant}")
	private String merchant;

	*/
/**
	 * 公钥
	 *//*

	@Value(value = "${weiqiatong.publicKey}")
	private String publicKey;

	*/
/**
	 * 私钥
	 *//*

	@Value(value = "${weiqiatong.privateKey}")
	private String privateKey;

	@Value(value = "${weiqiatong.callbackUrl}")
	private String callbackUrl;

	@Autowired
	private LoanProductRepository loanProductRepository;
	@Autowired
	private LoanOrderRepository loanOrderRepository;

	@Autowired
    private FeignRedisServiceClient feignRedisServiceClient;
	@Autowired
	private FeignNoticeSendClient feignNoticeSendClient;
	@Autowired
	private FeignUserServiceClient feignUserServiceClient;
	@Autowired
	private FeignProfitTaskServiceClient feignProfitTaskServiceClient;
	@Autowired
	private UploadService uploadService;
	@Autowired
    private FeignRealNameAuthServiceClient feignRealNameAuthServiceClient;
	@Autowired
	private FeignAgentialAccountServiceClient feignAgentialAccountServiceClient;
	@Autowired
	private FeignUserRelationServiceClient feignUserRelationServiceClient;


	@Value("${fastdfs.base.url}")
    private String FASTDFS_BASE_URL;

	@Value(value = "${loan.platform.profitPercent}")
	private String profitPercent;


	@RequestMapping(method = RequestMethod.POST, value = "/m2.0/loan/loanRanking")
	public List<LeaderBoardJpaDTO> loanRanking(@RequestParam(value = "brandId", required=true) Long brandId) {
		Pageable pageable = PageRequest.of(0,6);
		org.springframework.data.domain.Page<LeaderBoardJpaDTO> leaderBoardJpaDTOS = loanOrderRepository.loanRanking(pageable,brandId);
		List<LeaderBoardJpaDTO> content = leaderBoardJpaDTOS.getContent();
		return content;
	}


	@Override
	@ApiOperation(value = "同步第三方网贷通道接口")
	@RequestMapping(method = RequestMethod.POST, value = "/m2.0/loan/getChannelListFromThird")
	public void getChannelListFromThird() {

		String url = baseHost + "/loan/open/loan/product/price";
		// 生成时间戳
		String timestamp = String.valueOf(System.currentTimeMillis());
		// 公钥加密
		String sign = RsaUtils.encrypt(publicKey, String.valueOf(timestamp));
		// 建立请求头部数据
		Map<String, String> baseMap = new HashMap<>();
		baseMap.put("X-Auth-OEM", oemID);
		baseMap.put("X-Open-Sign", sign);
		baseMap.put("X-Open-Merchant", merchant);
		baseMap.put("X-Open-Timestamp", timestamp);

		logger.info("baseMap=" + baseMap.toString() +" url=" + url + " timestamp=" + timestamp + ",sign=" + sign + ",同步网贷解析结果=" + RsaUtils.decrypt(privateKey, sign));

		Map<String, Object> map = new HashMap<>();
		String json = JSON.toJSONString(map);
		// 建立post请求
		String resultText = HttpClient.doPost(url, baseMap, json);

		logger.info("同步通道resultText={}" + resultText);
		JSONObject object = null;
		try {
			object = JSONObject.parseObject(resultText);
		} catch (Exception e) {
			logger.error("getChannelListFromThird JSONObject parseObject error");
		}
		if(object == null) {
			return;
		}
		List<String> channelIdList = new ArrayList<>();
		if (object.containsKey("status")) {
			String status = object.getString("status");
			if (CommonConstants.LEY_RESULT_SUCCESS.equals(status)) {
				JSONArray array = JSONArray.parseArray(object.getString("result"));
				for (int i = 0; i < array.size(); i++) {
					String channelId = array.getJSONObject(i).getString("id");
					String channelName = array.getJSONObject(i).getString("name");

					String productId = array.getJSONObject(i).getJSONObject("platformProduct").getString("id");
					String productName = array.getJSONObject(i).getJSONObject("platformProduct").getString("name");
					String iconPath = array.getJSONObject(i).getJSONObject("platformProduct").getString("iconPath");
					String remark = array.getJSONObject(i).getJSONObject("platformProduct").getString("remark");
					String enable = array.getJSONObject(i).getJSONObject("platformProduct").getString("enable");
					String profitType = array.getJSONObject(i).getJSONObject("platformProduct").getString("profitType");
					Integer sort = array.getJSONObject(i).getJSONObject("platformProduct").getInteger("sort");

					BigDecimal quotaMax = array.getJSONObject(i).getJSONObject("platformProduct")
							.getBigDecimal("quotaMax").divide(new BigDecimal(100), 2, BigDecimal.ROUND_HALF_UP);
					BigDecimal quotaMin = array.getJSONObject(i).getJSONObject("platformProduct")
							.getBigDecimal("quotaMin").divide(new BigDecimal(100), 2, BigDecimal.ROUND_HALF_UP);;

					TLoanProduct product = new TLoanProduct();
					logger.info(channelId + "--" + channelName + "--" + productId + "--" + productName + "--" + iconPath
							+ "--" + remark + "--" + enable + "--" + profitType + "--" + "--" + quotaMax + "--"
							+ quotaMin);

					product.setChannelId(channelId);
					product.setChannelName(channelName);
					product.setProductId(productId);
					product.setProductName(productName);
					product.setProductIconPath(iconPath);
					product.setChannelDescription(remark);
					Integer thirdStatus = 0;
					if ("ACTIVATE".equalsIgnoreCase(enable)) {
						thirdStatus = 1;
					}
					product.setThirdStatus(thirdStatus);
					product.setProductProfitType(profitType);
					product.setMinLoanmoney(quotaMin);
					product.setMaxLoanMoney(quotaMax);

					product.setSort(sort);
					product.setStatus(0);

					TLoanProduct loanProduct = loanProductRepository.queryTLoanProductByProductId(productId);
					if (loanProduct != null) {
						product.setId(loanProduct.getId());
						product.setUpdateTime(new Date());
						UpdateTool.copyProperties(loanProduct, product);
					} else {
						product.setCreateTime(new Date());
					}


					product.setMarketId(MarketTypeEnum.TYPE_WECHARTTONG.getKey());
					loanProductRepository.save(product);

					channelIdList.add(channelId);
				}
			}
		} else {
			logger.error("getChannelListFromThird return data execption resultText={}", resultText);
		}
		if(channelIdList != null && channelIdList.size() > 0) {
			loanProductRepository.updateTLoanProductByChannelId(channelIdList);
		}
	}

	@Override
	@ApiOperation(value = "提交第三方订单通道接口")
	@RequestMapping(method = RequestMethod.POST, value = "/m2.0/loan/saveChannelOrderToThird")
	public String saveChannelOrderToThird(@RequestParam(value = "userPhone", required=true) String userPhone,
			@RequestParam(value = "channelId", required=true) String channelId,
			@RequestParam(value = "clientNo", required=true) String clientNo) {
		String url = baseHost + "/loan/open/loan/product/save";
		// 生成时间戳
		String timestamp = String.valueOf(System.currentTimeMillis());
		// 公钥加密
		String sign = RsaUtils.encrypt(publicKey, String.valueOf(timestamp));
		// 建立请求头部数据
		Map<String, String> baseMap = new HashMap<>();
		baseMap.put("X-Auth-OEM", oemID.toString());
		baseMap.put("X-Open-Sign", sign);
		baseMap.put("X-Open-Merchant", merchant);
		baseMap.put("X-Open-Timestamp", timestamp);
		// 建立请求数据
		Map<String, Object> map = new HashMap<>();
		// 申请人手机号
		map.put("mobile", userPhone);
		// 通道id 网贷列表的id
		map.put("oemChannelId", channelId);
		// 回调地址
		map.put("callbackUrl", callbackUrl);
		// 客户端编号，唯一请求标识
		map.put("clientNo", clientNo);

		logger.info("timestamp=" + timestamp + ",sign=" + sign + ",保存订单解析结果=" + RsaUtils.decrypt(privateKey, sign));
		// 建立post请求 传递json格式参数
		String resultText = HttpClient.doPost(url, baseMap, JSON.toJSONString(map));
		logger.info("保存订单resultText={}" + resultText);

		JSONObject object = null;
		try {
			object = JSONObject.parseObject(resultText);
		} catch (Exception e) {
			logger.error("saveChannelOrderToThird JSONObject parseObject error");
		}
		String message = null;
		if(object == null) {
			return "服务异常";
		}

		if (object.containsKey("status")) {
			String status = object.getString("status");
			TLoanOrder tLoanOrder = loanOrderRepository.queryTLoanOrderByClientNumber(clientNo);
			if (CommonConstants.LEY_RESULT_SUCCESS.equals(status)) {
				JSONObject objectResult = JSONObject.parseObject(object.getString("result"));
				String transNo = objectResult.getString("transNo");
				String customerServiceUrlPath = objectResult.getString("url");

				tLoanOrder.setLoanUrl(customerServiceUrlPath);
				tLoanOrder.setStatus(LoanOrderStatusTypeEnum.TYPE_STATUS_SUBMIT.getKey());
				tLoanOrder.setSubmitTime(new Date());
				tLoanOrder.setTransNumber(transNo);

				message = customerServiceUrlPath;
			} else {
				logger.error("saveChannelOrderToThird return data execption resultText={}", resultText);
				tLoanOrder.setLoanUrl(null);
				tLoanOrder.setStatus(LoanOrderStatusTypeEnum.TYPE_STAUTS_FAILURE.getKey());
				tLoanOrder.setSubmitTime(new Date());
				tLoanOrder.setTransNumber(null);
				message = object.getString("message");
				tLoanOrder.setFailureMassage(message);
			}
			loanOrderRepository.saveAndFlush(tLoanOrder);
		}
		return message;

	}

	@Override
	@ApiOperation(value = "获取网贷通道接口")
	@ApiImplicitParams({
			@ApiImplicitParam(name = "pageNum", value = "页码", dataType = "int", required = true, paramType = "query"),
			@ApiImplicitParam(name = "pageSize", value = "每页多少条", dataType = "int", required = true, paramType = "query"),
			@ApiImplicitParam(name = "productName", value = "产品名称(模糊查询)", required = false, dataType = "string", paramType = "query"),
			@ApiImplicitParam(name="status",value="0:未上架 1：已上架", required = false, dataType="int", paramType = "query")})
	@RequestMapping(method = RequestMethod.POST, value = "/m2.0/loan/getProductPageList")
	public Page<TLoanProduct> getProductPageList(
			@RequestParam(value = "pageNum", required=true) Integer pageNum,
    		@RequestParam(value = "pageSize", required=true) Integer pageSize,
			@RequestParam(value = "productName", required = false) String productName,
			@RequestParam(value = "status", required=false) Integer status) {
		Specification<TLoanProduct> specification=new Specification<TLoanProduct>() {

			private static final long serialVersionUID = 1L;

			@Override
			public Predicate toPredicate(Root<TLoanProduct> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
				List<Predicate> predicates = new ArrayList<Predicate>();

				if(StringUtils.isNoneBlank(productName)) {
					predicates.add(criteriaBuilder.like(root.get("productName"),"%"+productName+"%"));
				}
				if(status != null) {
					predicates.add(criteriaBuilder.equal(root.get("status"), status));
				}
				Predicate[] pre = new Predicate[predicates.size()];
				query.orderBy(criteriaBuilder.asc(root.get("sort")));
				return query.where(predicates.toArray(pre)).getRestriction();
			}
		};
		Pageable pageable = new PageRequest(pageNum == 0 ? pageNum : pageNum - 1, pageSize);
		org.springframework.data.domain.Page<TLoanProduct> page = loanProductRepository.findAll(specification, pageable);
		pageNum = (pageNum == 0 ? 1 : pageNum);
		Page<TLoanProduct> localPage = new Page<>(page.getContent(), page.getTotalElements(), pageNum, page.getSize());
		List<TLoanProduct> list= localPage.getContent();
		for(TLoanProduct product : list) {
			product.setThirdStatussName(WechartStatusTypeEnum.getEnumByKey(product.getThirdStatus()).getValue());
			product.setStatusName(ChannelStatusTypeEnum.getEnumByKey(product.getStatus()).getValue());
		}
		return localPage;
	}

	@Override
	@ApiOperation(value = "更新通道接口")
	@ApiImplicitParams({
		  @ApiImplicitParam(name="userId",value="操作用户标识",dataType="int", required = true, paramType = "query"),
		  @ApiImplicitParam(name="id",value="通道标识",dataType="int", required = true, paramType = "query"),
		  @ApiImplicitParam(name="sort",value="通道排序",dataType="int", paramType = "query"),
		  @ApiImplicitParam(name="applyRequire",value="申请要求",dataType="string", paramType = "query"),
		  @ApiImplicitParam(name="productInroduce",value="产品介绍",dataType="string", paramType = "query"),
		  @ApiImplicitParam(name="commissionIntroduce",value="返佣说明",dataType="string", paramType = "query"),
		  @ApiImplicitParam(name="productRemark",value="产品备注",dataType="string", paramType = "query")})
	@RequestMapping(method = RequestMethod.POST, value = "/m2.0/loan/updateProductById")
	public int updateProductById(@RequestParam(value = "userId", required=true) Integer userId,
			@RequestParam(value = "id", required = true) Integer id,
			@RequestParam(value = "sort", required = false) Integer sort,
			@RequestParam(value = "applyRequire", required = false) String applyRequire,
			@RequestParam(value = "productInroduce", required = false) String productInroduce,
			@RequestParam(value = "commissionIntroduce", required = false) String commissionIntroduce,
			@RequestParam(value = "productRemark", required = false) String productRemark) {

		Optional<TLoanProduct> loanProduct = loanProductRepository.findById(id);
		TLoanProduct tLoanProduct = loanProduct.get();

		TLoanProduct product = new TLoanProduct();

		UpdateTool.copyProperties(tLoanProduct, product);

		product.setId(id);
		product.setSort(sort);
		product.setApplyRequire(applyRequire);
		product.setProductIntroduce(productInroduce);
		product.setCommissionIntroduce(commissionIntroduce);
		product.setProductRemark(productRemark);
		product.setUpdateUser(String.valueOf(userId));

		loanProductRepository.saveAndFlush(product);
		return 1;
	}


	@Override
	@ApiOperation(value = "查询通道详情接口")
	@ApiImplicitParams({
		  @ApiImplicitParam(name="id",value="通道标识",dataType="int", required = true, paramType = "query")})
	@RequestMapping(method = RequestMethod.POST, value = "/m2.0/loan/selectProductById")
	public TLoanProduct selectProductById(@RequestParam(value = "id", required = true) Integer id) {

		Optional<TLoanProduct> loanProduct = loanProductRepository.findById(id);
		TLoanProduct tLoanProduct = loanProduct.get();
		tLoanProduct.setThirdStatussName(WechartStatusTypeEnum.getEnumByKey(tLoanProduct.getThirdStatus()).getValue());
		tLoanProduct.setStatusName(ChannelStatusTypeEnum.getEnumByKey(tLoanProduct.getStatus()).getValue());
		return tLoanProduct;
	}

	@Override
	@ApiOperation(value = "通道上下架操作")
	@ApiImplicitParams({
		  @ApiImplicitParam(name="userId",value="操作用户标识",dataType="int", required = true, paramType = "query"),
		  @ApiImplicitParam(name="status",value="上下架状态：0：下架 1：上架",dataType="int", required = true, paramType = "query"),
		  @ApiImplicitParam(name="id",value="通道标识",dataType="int", required = true, paramType = "query")})
	@RequestMapping(method = RequestMethod.POST, value = "/m2.0/loan/updateStatusById")
	public int updateStatusById(@RequestParam(value = "userId", required=true) Integer userId,
			@RequestParam(value = "id", required = true)Integer id,
			@RequestParam(value = "status", required = true) Integer status) {

		Optional<TLoanProduct> loanProduct = loanProductRepository.findById(id);
		if(loanProduct == null) {
			throw new RuntimeException("参数异常");
		}
		TLoanProduct tLoanProduct = loanProduct.get();

		if(tLoanProduct == null) {
			throw new RuntimeException("参数异常");
		}

		TLoanProduct product = new TLoanProduct();
		UpdateTool.copyProperties(tLoanProduct, product);
		if(status != 0 && status != 1) {
			throw new RuntimeException("参数异常");
		}
		product.setStatus(status);
		product.setUpdateUser(String.valueOf(userId));
		loanProductRepository.saveAndFlush(product);
		return 1;
	}

	private static final String redisSmsCode = "loan:marvel:sms";
	@Override
	@ApiOperation(value = "保存网贷订单到本地")
	@ApiImplicitParams({
		  @ApiImplicitParam(name="userId",value="用户标识",dataType="int", required = true, paramType = "query"),
		  @ApiImplicitParam(name="userName",value="用户名",dataType="string", required = true, paramType = "query"),
		  @ApiImplicitParam(name="userPhone",value="手机号",dataType="string", required = true, paramType = "query"),
		  @ApiImplicitParam(name="idCard",value="身份证号",dataType="string", required = false, paramType = "query"),
		  @ApiImplicitParam(name="channelId",value="通道标识",dataType="string", required = true, paramType = "query"),
		  @ApiImplicitParam(name="smsCode",value="短信验证码",dataType="string", required = true, paramType = "query"),
		  @ApiImplicitParam(name="source",value="订单来源",dataType="string", required = true, paramType = "query")})
	@RequestMapping(method = RequestMethod.POST, value = "/m2.0/loan/saveChannelOrder")
	public String saveChannelOrder(
			@RequestParam(value = "userId", required = true) Integer userId,
			@RequestParam(value = "userName", required = true) String userName,
			@RequestParam(value = "userPhone", required = true) String userPhone,
			@RequestParam(value = "idCard", required = false) String idCard,
			@RequestParam(value = "channelId", required = true) String channelId,
    		@RequestParam(value = "smsCode", required=true) String smsCode,
    		@RequestParam(value = "source", required=true) String source) {

		*/
/**
		 * 验证码识别
		 *//*

		String frontSms = feignRedisServiceClient.get(redisSmsCode + userPhone);
		if(frontSms == null || !frontSms.equals(smsCode)) {
			throw new RuntimeException("手机验证码错误");
		} else {
			feignRedisServiceClient.del(redisSmsCode + userPhone);
		}

		if(idCard != null && !VerifyUtil.cardCodeVerifySimple(idCard)) {
			throw new RuntimeException("身份证号格式错误");
		}

		if(!VerifyUtil.isPhone(userPhone)) {
			throw new RuntimeException("手机号格式错误");
		}

		TLoanProduct tLoanProduct = loanProductRepository.queryTLoanProductByChannelId(channelId);
		TLoanOrder order = new TLoanOrder();
		order.setMarketId(tLoanProduct.getMarketId());
		TUser tuser = feignUserServiceClient.getUserID(userId);
		if(tuser == null) {
			throw new RuntimeException("用户不存在");
		}
		order.setBrandId(tuser.getBrandId());
		order.setUserId(userId);
		if("null".equalsIgnoreCase(userName)) {
			userName = null;
		}
		order.setUserName(userName);
		order.setUserPhone(userPhone);
		order.setSource(source);

		TRealNameAuth auth = feignRealNameAuthServiceClient.queryRealnameAuthInfo(Long.valueOf(String.valueOf(userId)));
		if(auth == null && StringUtils.isBlank(idCard)) {
			throw new RuntimeException("请填写身份证号信息");
		}
		order.setIdCard((idCard == null) ? auth.getIdcard() : idCard);
		order.setProductProfitType(tLoanProduct.getProductProfitType());
		order.setProfitPerMoney(tLoanProduct.getProfitPerMoney());
		order.setChannelId(channelId);
		order.setChannelName(tLoanProduct.getChannelName());
		order.setStatus(LoanOrderStatusTypeEnum.TYPE_STAUTS_INIT.getKey());
		order.setCallbackUrl(callbackUrl);
		order.setCreateTime(new Date());
		String clientNumber = OrderNoUtil.getBuyOrderNo("L");
		order.setClientNumber(clientNumber);

		loanOrderRepository.saveAndFlush(order);

		String result = saveChannelOrderToThird(userPhone, channelId, clientNumber);

		if(result != null && (result.startsWith("http") || result.startsWith("HTTP"))) {
			feignRedisServiceClient.del(redisSmsCode + userPhone);
		}

		return result;
	}

	@Override
	@ApiOperation(value = "获取分页网贷订单列表")
	@ApiImplicitParams({
		  @ApiImplicitParam(name="pageNum",value="页码",dataType="int", required = true, paramType = "query"),
		  @ApiImplicitParam(name="pageSize",value="每页多少条",dataType="int", required = true, paramType = "query"),
		  @ApiImplicitParam(name="clientNumber",value="本地订单编号",dataType="string", paramType = "query"),
		  @ApiImplicitParam(name="userPhone",value="手机号",dataType="string", paramType = "query"),
		  @ApiImplicitParam(name="userId",value="用户标识",dataType="int", paramType = "query"),
		  @ApiImplicitParam(name="brandId",value="贴牌标识",dataType="long", paramType = "query"),
		  @ApiImplicitParam(name="status",value="订单状态",dataType="int", paramType = "query"),
			@ApiImplicitParam(name="agentUserId",value="代理商用户标示",dataType="int", paramType = "query")})
	@RequestMapping(method = RequestMethod.POST, value = "/m2.0/loan/getLoanOrderPageList")
	public Page<TLoanOrder> getLoanOrderPageList(@RequestParam(value = "pageNum", required=true) Integer pageNum,
    		@RequestParam(value = "pageSize", required=true) Integer pageSize,
    		@RequestParam(value = "clientNumber", required=false) String clientNumber,
    		@RequestParam(value = "userPhone", required=false) String userPhone,
    		@RequestParam(value = "userId", required=false) Integer userId,
    		@RequestParam(value = "brandId", required=false) Long brandId,
    		@RequestParam(value = "status", required=false) Integer status,
			@RequestParam(value = "agentUserId", required=false) Integer agentUserId) {
		List<Integer> subUserIdList = null;
		if(agentUserId != null) {
			subUserIdList = feignUserRelationServiceClient.querySubordinateUserIds(agentUserId);
		}
		List<Integer> finalSubUserIdList = subUserIdList;
		if(agentUserId != null && (finalSubUserIdList == null || finalSubUserIdList.size() == 0)) {
			return new Page<TLoanOrder>();
		}
		Specification<TLoanOrder> specification=new Specification<TLoanOrder>() {
			private static final long serialVersionUID = 1L;
			@Override
			public Predicate toPredicate(Root<TLoanOrder> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
				List<Predicate> predicates = new ArrayList<Predicate>();
				if(StringUtils.isNoneBlank(clientNumber)) {
					predicates.add(criteriaBuilder.equal(root.get("clientNumber"), clientNumber));
				}
				if(StringUtils.isNoneBlank(userPhone)) {
					predicates.add(criteriaBuilder.equal(root.get("userPhone"), userPhone));
				}
				if(userId != null) {
					predicates.add(criteriaBuilder.equal(root.get("userId"), userId));
				}
				if(brandId != null) {
					predicates.add(criteriaBuilder.equal(root.get("brandId"), brandId));
				}
				if(status != null) {
					predicates.add(criteriaBuilder.equal(root.get("status"), status));
				}
				if(finalSubUserIdList != null && finalSubUserIdList.size() > 0) {
					Path<Object> path = root.get("userId");
					CriteriaBuilder.In<Object> in = criteriaBuilder.in(path);
					for(Integer id : finalSubUserIdList) {
						in.value(id);
					}
					predicates.add(criteriaBuilder.and(in));
				}
				Predicate[] pre = new Predicate[predicates.size()];
				query.orderBy(criteriaBuilder.desc(root.get("id")));
				return query.where(predicates.toArray(pre)).getRestriction();
			}
		};
		Pageable pageable = new PageRequest(pageNum == 0 ? pageNum : pageNum -1, pageSize);
		org.springframework.data.domain.Page<TLoanOrder> page=  loanOrderRepository.findAll(specification, pageable);
		pageNum = (pageNum == 0 ? 1 : pageNum);
		Page<TLoanOrder> localPage = new Page<>(page.getContent(), page.getTotalElements(), pageNum, page.getSize());
		List<TLoanOrder> list = localPage.getContent();
		list.stream().forEach(order -> {
			order.setUserPhone(order.getUserPhone().replace(order.getUserPhone().substring(3, order.getUserPhone().length() - 4), "****"));
			order.setIdCard(order.getIdCard().replace(order.getIdCard().substring(1, order.getIdCard().length() - 1), "****************"));
			order.setStatusName(LoanOrderStatusTypeEnum.getEnumByKey(order.getStatus()).getValue());
		});
		return localPage;
	}

	private static final String redisValidateCode = "loan:marvel:validatecode";
	@Override
	@ApiOperation(value = "获取网贷验证码")
	@ApiImplicitParams({
		  @ApiImplicitParam(name="userPhone",value="手机号", required = true, dataType="string", paramType = "query")})
	@RequestMapping(method = RequestMethod.POST, value = "/m2.0/loan/validateCode")
	public String validateCode(@RequestParam(value = "userPhone", required=true) String userPhone) {
		// 生成随机字串
		String verifyCode = VerifyCodeUtils.generateVerifyCode(4);
		feignRedisServiceClient.set(redisValidateCode + userPhone, verifyCode, 5 * 60);
		logger.info("loan validateCode userPhone={} verifyCode={}", userPhone, verifyCode);
		return verifyCode;
	}

	@Override
	@ApiOperation(value = "获取网贷手机验证码")
	@ApiImplicitParams({
		  @ApiImplicitParam(name="userPhone",value="手机号", required = true, dataType="string", paramType = "query"),
		  @ApiImplicitParam(name="validateCode",value="图形验证码", required = true, dataType="string", paramType = "query"),
		  @ApiImplicitParam(name="brandId",value="贴牌标识", required = true, dataType="long", paramType = "query")})
	@RequestMapping(method = RequestMethod.POST, value = "/m2.0/loan/smsCode")
	public Boolean smsCode(@RequestParam(value = "userPhone", required=true) String userPhone,
			@RequestParam(value = "validateCode", required=true) String validateCode,
			@RequestParam(value = "brandId", required=true) Long brandId) {
		String redisValateCode = feignRedisServiceClient.get(redisValidateCode + userPhone);
		if(!validateCode.equals(redisValateCode)) {
			throw new RuntimeException("图形验证码错误");
		}
		if(!VerifyUtil.isPhone(userPhone)) {
			throw new RuntimeException("手机号格式错误");
		}
		String smsCode = VerifyCodeUtils.generateVerifyCode(6);
		feignRedisServiceClient.set(redisSmsCode + userPhone, smsCode, 5 * 60);
		feignNoticeSendClient.sendNotice(userPhone, new String[]{smsCode}, NoticeTpIIdEnum.TYPE_NOTICE_TPLID.getValue(), brandId);
		return true;
	}

	//查找总代理
	private TUserAgential findAgentialKing(Long userId){
		TUser user = feignUserServiceClient.queryUser(userId);
		if (user == null){
			logger.info("用户{}不存在，未查询到总代理商！",userId);
			return null;
		}
		TUserAgential userAgential = feignUserServiceClient.findAgentialKingBySysUserId(userId);
		if(userAgential == null) {
			if (user.getPreUserId()==null){
				logger.info("用户{}没有父级，查询总代理商结束！",userId);
				return null;
			}
			TUser nextUser = feignUserServiceClient.queryUser(user.getPreUserId());
			if(nextUser == null  || nextUser.getPreUserId() == null) {
				logger.info("用户{}不存在，未查询到总代理商！",user.getPreUserId());
				return null;
			}
			return findAgentialKing(nextUser.getId());
		}
		return userAgential;
	}

	@Override
	@ApiOperation(value = "网贷回调接口")
	@ApiImplicitParams({
		  @ApiImplicitParam(name="jsonText",value="接收的回调字符串", required = true, dataType="string", paramType = "query")})
	@RequestMapping(method = RequestMethod.POST, value = "/m2.0/loan/loanCallBack")
	public boolean loanCallBack(@RequestParam(value = "jsonText", required=true) String jsonText) {
		logger.info("====================网贷回调开始===================jsonText={}", jsonText);

		JSONObject object = JSONObject.parseObject(jsonText);
		String callbackType = object.getString("callbackType");
		if(!"CALLBACK_SUCCESS".equals(callbackType)) {
			logger.info("====================网贷回调失败===================jsonText={}", jsonText);
			//回调类型不成功
			return false;
		}
		//验签
		String timestampColum = object.getString("timestamp");
		String signT = object.getString("sign");//第三方sign
		String timestamp = RsaUtils.decrypt(privateKey, signT);
		if(timestampColum.equals(timestamp)) {
			String clientNo = object.getString("clientNo");
//			String transNo = object.getString("transNo");
			String amount = object.getString("amount");
			String userPrice = object.getString("userPrice");

			TLoanOrder tLoanOrder = loanOrderRepository.queryTLoanOrderByClientNumber(clientNo);
			if(tLoanOrder.getStatus() == LoanOrderStatusTypeEnum.TYPE_STATUS_FINISH.getKey() || tLoanOrder.getStatus() == LoanOrderStatusTypeEnum.TYPE_STATUS_FENRUN.getKey()) {
				logger.info("====================网贷回调订单状态已经为终态===================clentNo={}", tLoanOrder.getClientNumber());
				return true;
			}
			BigDecimal userPerfitMoney = new BigDecimal(userPrice).divide(new BigDecimal("100"), 2, RoundingMode.FLOOR);
			tLoanOrder.setAmount(new BigDecimal(amount).divide(new BigDecimal("100"), 2, RoundingMode.FLOOR));
			tLoanOrder.setUserPrice(userPerfitMoney);
			tLoanOrder.setCallback_time(new Date());
			tLoanOrder.setStatus(LoanOrderStatusTypeEnum.TYPE_STATUS_FINISH.getKey());
			loanOrderRepository.saveAndFlush(tLoanOrder);

			//进行分润操作
			ProfitThreeForm threeForm = new ProfitThreeForm();

			threeForm.setOrderCode(clientNo);
			threeForm.setUserId(Long.valueOf(tLoanOrder.getUserId()));

			*/
/*//*
/给总代分润
			BigDecimal percent=new BigDecimal(profitPercent).divide(new BigDecimal("2"),2,BigDecimal.ROUND_HALF_DOWN);
			TUserAgential agentialKing=findAgentialKing(tLoanOrder.getUserId().longValue());
			if (agentialKing!=null){
				feignAgentialAccountServiceClient.agentialBalanceAddOrSub(agentialKing.getUserId(),agentialKing.getBrandId(),"0",null,null,userPerfitMoney.multiply(percent).setScale(2,BigDecimal.ROUND_HALF_DOWN), AgentialBalanceHistoryTypeEnum.CREDIT.getKey(),clientNo,tLoanOrder.getUserId().longValue());
				logger.info("=======================给userId为{} 总代 分润 {}==========================",agentialKing.getUserId(),userPerfitMoney.multiply(percent).setScale(2,BigDecimal.ROUND_HALF_DOWN));
				threeForm.setAmount(userPerfitMoney.subtract(userPerfitMoney.multiply(percent)).setScale(2, BigDecimal.ROUND_HALF_DOWN));
			}
			else {
				threeForm.setAmount(userPerfitMoney.subtract(userPerfitMoney.multiply(new BigDecimal(profitPercent))).setScale(2, BigDecimal.ROUND_HALF_DOWN));
			}*//*

			threeForm.setAmount(userPerfitMoney.subtract(userPerfitMoney.multiply(new BigDecimal(profitPercent))).setScale(2, BigDecimal.ROUND_HALF_DOWN));
			threeForm.setChannelId(9999);//手动加入id=9999
			threeForm.setBrandId(Integer.valueOf(tLoanOrder.getBrandId().toString()));
			threeForm.setProfitTypeId(2);
//			threeForm.setProfitLevel(0);
			Boolean result = feignProfitTaskServiceClient.processProfitThreeForm(threeForm);
			logger.info("====================网贷回调订单状态分润开始===================clentNo={}", tLoanOrder.getClientNumber());
			if(result) {
				TLoanOrder tLoanOrderFit = loanOrderRepository.queryTLoanOrderByClientNumber(clientNo);
				tLoanOrderFit.setStatus(LoanOrderStatusTypeEnum.TYPE_STATUS_FENRUN.getKey());
				tLoanOrderFit.setRebet_time(new Date());
				loanOrderRepository.saveAndFlush(tLoanOrder);
				logger.info("====================网贷回调订单状态分润结束===================clentNo={}", tLoanOrder.getClientNumber());
			} else {
				logger.info("====================网贷回调订单状态分润失败===================clentNo={}", tLoanOrder.getClientNumber());
			}
		} else {
			//验签失败
			logger.info("====================网贷回调订单状态验签失败===================jsonText={}", jsonText);
			return false;
		}
		logger.info("====================网贷回调结束===================jsonText={}", jsonText);
		return true;
	}

	@Override
	@ApiOperation(value = "获取已完成订单userId")
	@ApiImplicitParams({
			@ApiImplicitParam(name="brandId",value="贴牌标示", required = true, dataType="int", paramType = "query")})
	public List<Integer> queryTLoanOrderFinish(@RequestParam(value = "brandId", required=true) Long brandId) {
		return loanOrderRepository.queryTLoanOrderFinish(brandId);
	}

	@Override
	@ApiOperation(value = "获取网贷图片验证码")
	@ApiImplicitParams({
		  @ApiImplicitParam(name="userPhone",value="手机号", required = true, dataType="string", paramType = "query")})
	@RequestMapping(method = RequestMethod.POST, value = "/m2.0/loan/validateCodeStr")
	public String validateCodeStr(@RequestParam(value = "userPhone", required=true) String userPhone) {
		String verifyCode = VerifyCodeUtils.generateVerifyCode(4);
		feignRedisServiceClient.set(redisValidateCode + userPhone, verifyCode, 5 * 60);
		logger.info("loan validateCode userPhone={} verifyCode={}", userPhone, verifyCode);
		
		int width = 100;// 宽
		int height = 40;// 高
		String fileName = verifyCode + ".jpg";
		String path = this.getClass().getResource("/").getPath() + "/" + fileName;
		File file = new File(path);

		String url = "";
		try {
			VerifyCodeUtils.outputImage(width, height, file, verifyCode);
			
//			byte[] bytes = FileUtils.File2byte(file);
//			String byteStr = Base64.getEncoder().encodeToString(bytes);
//			url = feignFastdfsServiceClient.uploadFileStr(byteStr, fileName);
			
			url = uploadService.uploadFile(file);
		} catch (IOException e) {
			logger.error("validateCodeStr error", e);
		} finally {
			file.delete();
		}
		return FASTDFS_BASE_URL + url;
	}
}
*/
